using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using JGSY.CMS.LowCode.Platform.Application.Interfaces;

namespace JGSY.CMS.LowCode.Platform.Infrastructure.Services
{
    /// <summary>
    /// 本地存储服务实现
    /// </summary>
    public class LocalStorageService : ICloudStorageService
    {
        private readonly IWebHostEnvironment _environment;
        private readonly IConfiguration _configuration;
        private readonly ILogger<LocalStorageService> _logger;
        private readonly string _baseUploadPath;
        private readonly string _baseUrl;

        public LocalStorageService(
            IWebHostEnvironment environment,
            IConfiguration configuration,
            ILogger<LocalStorageService> logger)
        {
            _environment = environment;
            _configuration = configuration;
            _logger = logger;
            
            // 使用强类型配置映射器获取存储配置
            var mapper = new JGSY.CMS.LowCode.Platform.Infrastructure.Configuration.AppSettingsMapper(configuration);
            var uploadConfig = mapper.Bind<JGSY.CMS.LowCode.Platform.Infrastructure.Configuration.Models.UploadConfiguration>("Upload");
            
            _baseUploadPath = Path.Combine(_environment.WebRootPath, "uploads");
            _baseUrl = uploadConfig.Local.BaseUrl ?? "/uploads";
            
            // 确保上传目录存在
            if (!Directory.Exists(_baseUploadPath))
            {
                Directory.CreateDirectory(_baseUploadPath);
            }
        }

        public async Task<string> UploadAsync(Stream file, string fileName, string? folder = null, string? contentType = null)
        {
            try
            {
                var sanitizedFileName = SanitizeFileName(fileName);
                var relativePath = BuildRelativePath(folder, sanitizedFileName);
                var fullPath = Path.Combine(_baseUploadPath, relativePath);
                
                // 确保目录存在
                var directory = Path.GetDirectoryName(fullPath);
                if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
                {
                    Directory.CreateDirectory(directory);
                }

                // 处理文件名冲突
                fullPath = await EnsureUniqueFileNameAsync(fullPath);
                relativePath = Path.GetRelativePath(_baseUploadPath, fullPath);

                // 保存文件
                using var fileStream = new FileStream(fullPath, FileMode.Create);
                await file.CopyToAsync(fileStream);
                
                var fileUrl = BuildFileUrl(relativePath);
                
                _logger.LogInformation("文件上传成功: {FileName} -> {FilePath}", fileName, fileUrl);
                
                return fileUrl;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "文件上传失败: {FileName}", fileName);
                throw;
            }
        }

        public async Task<string> UploadAsync(IFormFile file, string? folder = null)
        {
            if (file == null || file.Length == 0)
            {
                throw new ArgumentException("文件不能为空", nameof(file));
            }

            using var stream = file.OpenReadStream();
            return await UploadAsync(stream, file.FileName, folder, file.ContentType);
        }

        public async Task<List<string>> UploadBatchAsync(IEnumerable<IFormFile> files, string? folder = null)
        {
            var results = new List<string>();
            
            foreach (var file in files)
            {
                if (file?.Length > 0)
                {
                    try
                    {
                        var url = await UploadAsync(file, folder);
                        results.Add(url);
                    }
                    catch (Exception ex)
                    {
                        _logger.LogError(ex, "批量上传中文件失败: {FileName}", file.FileName);
                        // 继续处理其他文件
                    }
                }
            }

            return results;
        }

        public Task<Stream> DownloadAsync(string fileUrl)
        {
            try
            {
                var relativePath = ExtractRelativePathFromUrl(fileUrl);
                var fullPath = Path.Combine(_baseUploadPath, relativePath);
                
                if (!File.Exists(fullPath))
                {
                    throw new FileNotFoundException($"文件不存在: {fileUrl}");
                }

                var stream = new FileStream(fullPath, FileMode.Open, FileAccess.Read);
                return Task.FromResult<Stream>(stream);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "文件下载失败: {FileUrl}", fileUrl);
                throw;
            }
        }

        public Task<bool> DeleteAsync(string fileUrl)
        {
            try
            {
                var relativePath = ExtractRelativePathFromUrl(fileUrl);
                var fullPath = Path.Combine(_baseUploadPath, relativePath);
                
                if (File.Exists(fullPath))
                {
                    File.Delete(fullPath);
                    
                    // 尝试删除空目录
                    TryDeleteEmptyDirectory(Path.GetDirectoryName(fullPath));
                    
                    _logger.LogInformation("文件删除成功: {FileUrl}", fileUrl);
                    return Task.FromResult(true);
                }

                return Task.FromResult(false);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "文件删除失败: {FileUrl}", fileUrl);
                return Task.FromResult(false);
            }
        }

        public async Task<int> DeleteBatchAsync(IEnumerable<string> fileUrls)
        {
            var successCount = 0;
            
            foreach (var fileUrl in fileUrls)
            {
                try
                {
                    if (await DeleteAsync(fileUrl))
                    {
                        successCount++;
                    }
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "批量删除中文件失败: {FileUrl}", fileUrl);
                }
            }

            return successCount;
        }

        public Task<bool> ExistsAsync(string fileUrl)
        {
            try
            {
                var relativePath = ExtractRelativePathFromUrl(fileUrl);
                var fullPath = Path.Combine(_baseUploadPath, relativePath);
                return Task.FromResult(File.Exists(fullPath));
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "检查文件存在性失败: {FileUrl}", fileUrl);
                return Task.FromResult(false);
            }
        }

        public Task<CloudFileInfo?> GetFileInfoAsync(string fileUrl)
        {
            try
            {
                var relativePath = ExtractRelativePathFromUrl(fileUrl);
                var fullPath = Path.Combine(_baseUploadPath, relativePath);
                
                if (!File.Exists(fullPath))
                {
                    return Task.FromResult<CloudFileInfo?>(null);
                }

                var fileInfo = new FileInfo(fullPath);
                var cloudFileInfo = new CloudFileInfo
                {
                    FileName = fileInfo.Name,
                    FilePath = relativePath,
                    Url = fileUrl,
                    Size = fileInfo.Length,
                    LastModified = fileInfo.LastWriteTime,
                    CreatedAt = fileInfo.CreationTime,
                    ContentType = GetContentType(fileInfo.Extension)
                };

                return Task.FromResult<CloudFileInfo?>(cloudFileInfo);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "获取文件信息失败: {FileUrl}", fileUrl);
                return Task.FromResult<CloudFileInfo?>(null);
            }
        }

        public Task<PreSignedUploadInfo> GeneratePreSignedUploadUrlAsync(string fileName, string? folder = null, TimeSpan? expiration = null)
        {
            // 本地存储不支持预签名URL，返回常规上传信息
            var info = new PreSignedUploadInfo
            {
                UploadUrl = "/api/media/upload",
                FileUrl = BuildFileUrl(BuildRelativePath(folder, SanitizeFileName(fileName))),
                ExpiresAt = DateTime.UtcNow.Add(expiration ?? TimeSpan.FromHours(1))
            };

            return Task.FromResult(info);
        }

        public Task<string> GeneratePreSignedDownloadUrlAsync(string fileUrl, TimeSpan? expiration = null)
        {
            // 本地存储直接返回文件URL
            return Task.FromResult(fileUrl);
        }

        public Task<List<CloudFileInfo>> ListFilesAsync(string? folder = null, int maxResults = 100)
        {
            try
            {
                var searchPath = string.IsNullOrEmpty(folder) 
                    ? _baseUploadPath 
                    : Path.Combine(_baseUploadPath, folder);

                if (!Directory.Exists(searchPath))
                {
                    return Task.FromResult(new List<CloudFileInfo>());
                }

                var files = Directory.GetFiles(searchPath, "*", SearchOption.AllDirectories)
                    .Take(maxResults)
                    .Select(fullPath =>
                    {
                        var fileInfo = new FileInfo(fullPath);
                        var relativePath = Path.GetRelativePath(_baseUploadPath, fullPath);
                        
                        return new CloudFileInfo
                        {
                            FileName = fileInfo.Name,
                            FilePath = relativePath,
                            Url = BuildFileUrl(relativePath),
                            Size = fileInfo.Length,
                            LastModified = fileInfo.LastWriteTime,
                            CreatedAt = fileInfo.CreationTime,
                            ContentType = GetContentType(fileInfo.Extension)
                        };
                    })
                    .ToList();

                return Task.FromResult(files);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "列出文件失败: {Folder}", folder);
                return Task.FromResult(new List<CloudFileInfo>());
            }
        }

        public async Task<string> CopyAsync(string sourceUrl, string destinationPath)
        {
            try
            {
                var sourceRelativePath = ExtractRelativePathFromUrl(sourceUrl);
                var sourceFullPath = Path.Combine(_baseUploadPath, sourceRelativePath);
                
                if (!File.Exists(sourceFullPath))
                {
                    throw new FileNotFoundException($"源文件不存在: {sourceUrl}");
                }

                var destFullPath = Path.Combine(_baseUploadPath, destinationPath);
                var destDirectory = Path.GetDirectoryName(destFullPath);
                
                if (!string.IsNullOrEmpty(destDirectory) && !Directory.Exists(destDirectory))
                {
                    Directory.CreateDirectory(destDirectory);
                }

                destFullPath = await EnsureUniqueFileNameAsync(destFullPath);
                File.Copy(sourceFullPath, destFullPath);
                
                var destRelativePath = Path.GetRelativePath(_baseUploadPath, destFullPath);
                var destUrl = BuildFileUrl(destRelativePath);
                
                _logger.LogInformation("文件复制成功: {Source} -> {Destination}", sourceUrl, destUrl);
                
                return destUrl;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "文件复制失败: {Source} -> {Destination}", sourceUrl, destinationPath);
                throw;
            }
        }

        public async Task<string> MoveAsync(string sourceUrl, string destinationPath)
        {
            try
            {
                var destUrl = await CopyAsync(sourceUrl, destinationPath);
                await DeleteAsync(sourceUrl);
                
                _logger.LogInformation("文件移动成功: {Source} -> {Destination}", sourceUrl, destUrl);
                
                return destUrl;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "文件移动失败: {Source} -> {Destination}", sourceUrl, destinationPath);
                throw;
            }
        }

        public Task<StorageStatistics> GetStatisticsAsync(string? folder = null)
        {
            try
            {
                var searchPath = string.IsNullOrEmpty(folder) 
                    ? _baseUploadPath 
                    : Path.Combine(_baseUploadPath, folder);

                if (!Directory.Exists(searchPath))
                {
                    return Task.FromResult(new StorageStatistics());
                }

                var files = Directory.GetFiles(searchPath, "*", SearchOption.AllDirectories);
                var totalSize = files.Sum(f => new FileInfo(f).Length);
                
                var fileTypeStats = files
                    .GroupBy(f => Path.GetExtension(f).ToLowerInvariant())
                    .ToDictionary(
                        g => g.Key,
                        g => new FileTypeStats 
                        { 
                            Count = g.Count(), 
                            TotalSize = g.Sum(f => new FileInfo(f).Length) 
                        });

                var stats = new StorageStatistics
                {
                    TotalFiles = files.Length,
                    TotalSize = totalSize,
                    FileTypeStats = fileTypeStats
                };

                return Task.FromResult(stats);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "获取存储统计失败: {Folder}", folder);
                return Task.FromResult(new StorageStatistics());
            }
        }

        private string SanitizeFileName(string fileName)
        {
            var invalidChars = Path.GetInvalidFileNameChars();
            var sanitized = new string(fileName.Where(c => !invalidChars.Contains(c)).ToArray());
            
            // 如果文件名为空或只包含无效字符，生成一个默认名称
            if (string.IsNullOrWhiteSpace(sanitized))
            {
                sanitized = $"file_{Guid.NewGuid():N}{Path.GetExtension(fileName)}";
            }

            return sanitized;
        }

        private string BuildRelativePath(string? folder, string fileName)
        {
            if (string.IsNullOrEmpty(folder))
            {
                return fileName;
            }

            // 清理文件夹路径
            folder = folder.Replace('\\', '/').Trim('/');
            return Path.Combine(folder, fileName).Replace('\\', '/');
        }

        private string BuildFileUrl(string relativePath)
        {
            return $"{_baseUrl.TrimEnd('/')}/{relativePath.Replace('\\', '/')}";
        }

        private string ExtractRelativePathFromUrl(string fileUrl)
        {
            var baseUrlPart = _baseUrl.TrimEnd('/');
            if (fileUrl.StartsWith(baseUrlPart))
            {
                return fileUrl.Substring(baseUrlPart.Length + 1).Replace('/', Path.DirectorySeparatorChar);
            }
            
            throw new ArgumentException($"无效的文件URL: {fileUrl}");
        }

    private Task<string> EnsureUniqueFileNameAsync(string filePath)
        {
            if (!File.Exists(filePath))
            {
        return Task.FromResult(filePath);
            }

            var directory = Path.GetDirectoryName(filePath) ?? string.Empty;
            var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(filePath);
            var extension = Path.GetExtension(filePath);
            
            var counter = 1;
            string newFilePath;
            
            do
            {
                var newFileName = $"{fileNameWithoutExtension}_{counter}{extension}";
                newFilePath = Path.Combine(directory, newFileName);
                counter++;
            }
            while (File.Exists(newFilePath));

            return Task.FromResult(newFilePath);
        }

        private void TryDeleteEmptyDirectory(string? directoryPath)
        {
            if (string.IsNullOrEmpty(directoryPath) || !Directory.Exists(directoryPath))
            {
                return;
            }

            try
            {
                // 检查目录是否为空
                if (!Directory.EnumerateFileSystemEntries(directoryPath).Any())
                {
                    Directory.Delete(directoryPath);
                    
                    // 递归删除父级空目录
                    var parentDirectory = Path.GetDirectoryName(directoryPath);
                    if (parentDirectory != _baseUploadPath)
                    {
                        TryDeleteEmptyDirectory(parentDirectory);
                    }
                }
            }
            catch (Exception ex)
            {
                _logger.LogDebug(ex, "删除空目录时出错: {Directory}", directoryPath);
            }
        }

        private static string? GetContentType(string extension)
        {
            return extension.ToLowerInvariant() switch
            {
                ".jpg" or ".jpeg" => "image/jpeg",
                ".png" => "image/png",
                ".gif" => "image/gif",
                ".webp" => "image/webp",
                ".svg" => "image/svg+xml",
                ".pdf" => "application/pdf",
                ".txt" => "text/plain",
                ".html" => "text/html",
                ".css" => "text/css",
                ".js" => "application/javascript",
                ".json" => "application/json",
                ".xml" => "application/xml",
                ".zip" => "application/zip",
                ".rar" => "application/x-rar-compressed",
                ".7z" => "application/x-7z-compressed",
                ".mp4" => "video/mp4",
                ".avi" => "video/x-msvideo",
                ".mov" => "video/quicktime",
                ".mp3" => "audio/mpeg",
                ".wav" => "audio/wav",
                ".doc" => "application/msword",
                ".docx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
                ".xls" => "application/vnd.ms-excel",
                ".xlsx" => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
                ".ppt" => "application/vnd.ms-powerpoint",
                ".pptx" => "application/vnd.openxmlformats-officedocument.presentationml.presentation",
                _ => "application/octet-stream"
            };
        }
    }
}
